package com.atguigu.userprofile.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.userprofile.bean.TagCondition;
import com.atguigu.userprofile.bean.TagInfo;
import com.atguigu.userprofile.bean.UserGroup;
import com.atguigu.userprofile.constants.ConstCodes;
import com.atguigu.userprofile.mapper.UserGroupMapper;
import com.atguigu.userprofile.service.TagInfoService;
import com.atguigu.userprofile.service.UserGroupService;
import com.atguigu.userprofile.utils.RedisUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.apache.catalina.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangchen
 * @since 2021-05-04
 */
@Service
@Slf4j
@DS("mysql")
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {

    @Autowired
    TagInfoService tagInfoService;



    @Override
    public void saveUserGroupInfo(UserGroup userGroup) {
         //处理字段  条件保存为json
        List<TagCondition> tagConditions = userGroup.getTagConditions();
        String conditionJsonString = JSON.toJSONString(tagConditions);
        userGroup.setConditionJsonStr(conditionJsonString);

        userGroup.setCreateTime(new Date());
        userGroup.setConditionComment(userGroup.conditionJsonToComment());  //条件集合转为中文
        //保存
         super.saveOrUpdate(userGroup);
    }

    @Override
    public void genUserGroupUids(UserGroup userGroup) {
        // 产生人群包
        String insertBitmapSQL = genInsertBitmapSQL(userGroup);
        System.out.println(insertBitmapSQL);
        super.baseMapper.insertUserGroupBitmap(insertBitmapSQL);

        //写入redis之前 要把人群包的用户id提取成一个数组
        List<String> userIdList = super.baseMapper.selectUserGroupUidList(userGroup.getId().toString());
        // 将人群包  复制一份到redis中
        //如何存储人群包 在redis中？
        //type?   set   key ?   user_group:123   value?  uid   field/score? 无
        // 写?  sadd   读？  sismember  判存   smembers 全集     失效？ 计算结果一般不设失效    缓存或者临时数据设失效

        Jedis jedis = RedisUtil.getJedis();
        String usergroupKey="user_group:"+userGroup.getId();
        jedis.sadd(usergroupKey,userIdList.toArray(new String[]{}));
        jedis.close();

        //   更新人群信息
        //取人群包的人数
        Long userGroupCount = super.baseMapper.selectUserGroupCount(userGroup.getId().toString());
        userGroup.setUserGroupNum(userGroupCount);
        super.saveOrUpdate(userGroup);

    }

    @Override
    public Long userGroupEvaluate(UserGroup userGroup) {

        String bitmapSQL = genBitmapSQL(userGroup);
        String  bitmapCountSQL="  select bitmapCardinality( "+bitmapSQL+")";
        Long bitmapCount = super.baseMapper.selectBitmapCount(bitmapCountSQL);
        return bitmapCount;
    }

    @Override
    public void refreshUserGroup(String userGroupId, String busiDate) {
        //1 清楚旧的数据
        // ck     delete   //因为每个分群 就是一个分区 所以 删除分群其实就是删除一个分区 性能压力不大
        //  alter table user_group delete where user_group_id=''
        super.baseMapper.deleteUserGroup(userGroupId);
        // redis
        String usergroupKey="user_group:"+userGroupId;
        Jedis jedis = RedisUtil.getJedis();
        jedis.del(usergroupKey);
        jedis.close();
        //2 把mysql中对于分群的定义数据取出 UserGroup
        UserGroup userGroup = this.getById(userGroupId);
        String conditionJsonStr = userGroup.getConditionJsonStr();
        List<TagCondition> tagConditions = JSON.parseArray(conditionJsonStr, TagCondition.class);
        userGroup.setTagConditions(tagConditions);
        userGroup.setBusiDate(busiDate);
        //3 利用分群定义（主要 筛选条件） 再次生成人群包 （ck ,redis)
        genUserGroupUids(userGroup);



    }

    public String genInsertBitmapSQL(UserGroup userGroup){
        String bitmapSQL = genBitmapSQL(userGroup);
        String insertBitmapSQL="insert into user_group select '"+userGroup.getId()+"' user_group_id,  "+bitmapSQL;
        return insertBitmapSQL;

    }

    //在用bitmapAnd把子查询两两组合
    public String genBitmapSQL(UserGroup userGroup){
        Map<String, TagInfo> tagInfoMap = tagInfoService.getTagInfoMapWithCode();
        List<TagCondition> tagConditionList = userGroup.getTagConditions();

        StringBuilder bitmapSQL=new StringBuilder();
        for (TagCondition tagCondition : tagConditionList) {
            String conditionSQL = genConditionSQL(tagCondition,tagInfoMap,userGroup.getBusiDate());
            if(bitmapSQL.length()==0){
                bitmapSQL.insert(0,"(").append(conditionSQL).append(")");
            }else{
                bitmapSQL.insert(0,"bitmapAnd( ").append(",(").append(conditionSQL ).append("))");
            }
        }
        return bitmapSQL.toString();
    }


//    select  us from user_tag_value_string where tag_code='agegroup' and  tag_value='男’  and dt=‘2021-05-16’
//	1  表名 --> 标签值的类型 -->目前没有 去tag_info 查询  （ 提前查询到内存集合中）
//    2  标签编码  --> 条件中的标签编码
//	3  标签值    条件中的 tagValues
//    一个值  'xx'  或者多个值    ('xx' ,'xx')
//    加单引 或者不加  --> 标签值的类型  字符串 日期 加单引
//    4   符号 --> 根据 条件中的operator来 映射
//    5     时间  业务时间

    //根据某一个标签条件 生成对应的子查询
    private String  genConditionSQL(TagCondition tagCondition,Map<String,TagInfo> tagInfoMap,String busiDate){
        String tagCode = tagCondition.getTagCode();
        TagInfo tagInfo = tagInfoMap.get(tagCode);
        String tagValueType = tagInfo.getTagValueType();
        String tableName=null;
        if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_LONG)){
            tableName="user_tag_value_long";
        }else if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_DECIMAL)){
            tableName="user_tag_value_decimal";
        }else if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_STRING)){
            tableName="user_tag_value_string";
        }else if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_DATE)){
            tableName="user_tag_value_date";
        }

       //标签值处理
        List<String> tagValues = tagCondition.getTagValues();
        StringBuilder tagValueStringBuilder= new StringBuilder();
        for (String tagValue : tagValues) {
            if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_STRING) ||tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_DATE)){
                tagValue="'"+tagValue+"'";
            }
            if(tagValueStringBuilder.length()>0){
                tagValueStringBuilder.append(",");
            }
            tagValueStringBuilder.append(tagValue);
        }
        if(tagValues.size()>1){
            tagValueStringBuilder.insert(0,"(").append(")");
        }
        String tagValue=tagValueStringBuilder.toString();
        //判断符号处理
        String conditionOperator = getConditionOperator(tagCondition.getOperator());

        //拼接成sql
        String conditionSQL="select groupBitmapMergeState(us) from  "+tableName +" where  tag_code='"+tagCode+"'"
                + " and tag_value "+conditionOperator+" "+tagValue+ " and dt='"+ busiDate+"'";
        return   conditionSQL;
    }



    private  String getConditionOperator(String operator){
        switch (operator){
            case "eq":
                return "=";
            case "lte":
                return "<=";
            case "gte":
                return ">=";
            case "lt":
                return "<";
            case "gt":
                return ">";
            case "neq":
                return "<>";
            case "in":
                return "in";
            case "nin":
                return "not in";
        }
        throw  new RuntimeException("操作符不正确");
    }

}
